October 01, 2006

Grafting Rails Into an Existing Website: Navigation

I'm a big believer in the "Don't Repeat Yourself" (DRY) principle, as is the Rails team. One place this pops up is in our website's navigation. Like pretty much any site that grows beyond a few pages, we're including a navigation file into each page on the site. There isn't anything fancy going on here: we're just setting a few variables on each page (page name, section, subsection, and so on), then showing or hiding parts of the navigation "tree" accordingly.

There are (at least) two ways to do this: store the navigation information in the database or in a flat-file of some sort. I chose the latter method. Storing this info in a database can be expensive, in terms of the number of database calls required to generate each and every page. I don't think it is a great idea to build in a required 2-3 DB calls per hit, and a navigation caching system probably isn't worth the additional complication. So, we're storing the navigation "tree" in a series of nested PHP arrays and a bit of PHP code basically "walks" the tree, looking for matches to a given section or page name, producing the HTML navigation menu accordingly. It is fast and simple. The gotcha here is that this is *PHP* code. And now I want to use it for a Ruby on Rails app. I don't want to have to re-create the entire array in ruby, because maintaining two identical sets of source for the navigation would be, well, pretty stupid.

So, the solution was to write a bit of a PHP that will read the PHP array and convert it to ruby code. Then, I wrote a Rails helper to walk through the ruby version and generate the navigation menu in HTML. I set up a cron job to automatically run the translator from PHP to ruby, and the problem was solved! We're able to use the same source file (in PHP) to power both systems, and it doesn't require any extra thought on our part (thanks to the cron job).